#
# TCSS 422 - Spring 2013
# Paul Ganea, Ralph Feltis, Tarl Hahn
# Team: Something Awesome (We can't remember the exact name)
# 5/2/2013
#

#
# GUI class and starting point for the web crawler
#
from javax.swing import *
from java.awt import *
from java.awt.event import ActionListener, MouseAdapter, MouseListener
from MultiThreadedCrawler import MultiThreadedCrawler
from SingleThreadedCrawler import SingleThreadedCrawler
from javax.swing.event import ListSelectionListener;
from javax.swing.event import ListSelectionEvent;
from java.util import TimerTask
import time
import threading
import datetime
import sys
import java.awt.image.BufferedImage;

MAX_WORKERS = 100
MAX_MAXPAGES = 10000

REPORTER_PANEL_NAME = "reporter"
PAGES_PANEL_NAME = "pages"
LOG_PANEL_NAME = "log"

DEFAULT_BEAN_LABEL_TEXT = "Click a URL to display statistics!"

the_font= Font("Kristen ITC", Font.BOLD, 18)
## creates the background panel
class bgPanel(JPanel):
	def __init__(self):
		JPanel.__init__(self)
		#background panel init
		self.setLayout(CardLayout())
		self.setBackground(Color(255,255,255))

## dispaly panel classes.  This creates the crawler and stat display panels
class displayPanel(JPanel):
	def __init__(self):
		JPanel.__init__(self)
		SetStyle(self)


class switchMenuButton(JRadioButtonMenuItem):
	def __init__(self,text):
		JRadioButtonMenuItem.__init__(self,text,actionPerformed=self.singleMultiAction)
		self.setForeground(Color.GREEN)
		self.setBackground(Color.BLACK)
		self.setFont(the_font)
		
	def singleMultiAction(self,event):
		if(self.getText() == "Multi-Threaded" and self.isSelected()):
			frame.setThread(True)
		elif(self.getText() == "Single-Threaded" and self.isSelected()):
			frame.setThread(False)

## Starting point for the GUI initializes the frame
class GraphicUI(JFrame):	
	def __init__(self):
		JFrame.__init__(self)
		self.thread = True
		self.crawler = MultiThreadedCrawler(1,1)
		self.parsers=5
		self.retrievers=5
		self.maxPages=self.crawler.getMaxPages()
		self.setTitle("WebCrawler")
		self.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
		self.setSize(800, 600)
		self.setLocationRelativeTo(None)	
      
	def setThread(self,flag):
		self.thread=flag
	
	def startCrawling(self):
		if(frame.isThreaded()):
			self.crawler = MultiThreadedCrawler(frame.getRetrievers(),frame.getParsers())
		else:
			self.crawler = SingleThreadedCrawler()
		self.crawler.setMaxPages(frame.maxPages)
		## crawl
		self.crawler.Crawl(uiInputURL.getText())
		
		loggingThread = threading.Thread(target=lambda: printLog(), name="Logging Thread")
		loggingThread.isDaemon = True
		loggingThread.start()	
	
	def getMessage(self):
		return self.crawler.getLog().get(True, None)
	
	def isThreaded(self):
		return self.thread
	
	def getParsers(self):
		return self.parsers
	
	def getRetrievers(self):
		return self.retrievers
	
	def setParsers(self,num):
		try:   
			num = int(num)
			if num > 0:
				self.parsers=min(num, MAX_WORKERS)        
		except:
			pass
			
	def setRetrievers(self,newMax):
		try:   
			newMax = int(newMax)
			if newMax > 0:
				self.retrievers=min(newMax, MAX_WORKERS)         
		except:
			pass		
	
	def setPageLimit(self,newMax):
		try:   
			newMax = int(newMax)
			if newMax > 0:
				self.maxPages = min(newMax, MAX_MAXPAGES)         
		except:
			pass					
		
	def getPageLimit(self):
		return self.maxPages		
		
class crawlMenu(JMenuBar):
	def __init__(self):
		JMenuBar.__init__(self)		
		self.fileMenu = JMenu("File")
		SetStyle(self.fileMenu)

		self.viewMenu = JMenu("View")
		SetStyle(self.viewMenu)
		
		self.optionMenu = JMenu("Options")
		SetStyle(self.optionMenu)
		
		self.helpJMenu = JMenu("Help")
		SetStyle(self.helpJMenu)
		
		# Menu items for File		
		self.quitMenuItem = JMenuItem("Quit",actionPerformed=self.quitAction)
		SetStyle(self.quitMenuItem)
		self.fileMenu.add(self.quitMenuItem)
		
		# Menu items for View
		self.reporterViewMenuItem = JMenuItem("Reporter",actionPerformed=self.showReporterPanel)
		SetStyle(self.reporterViewMenuItem)
		self.viewMenu.add(self.reporterViewMenuItem)
		
		self.pagesViewMenuItem = JMenuItem("Pages",actionPerformed=self.showPagesPanel)
		SetStyle(self.pagesViewMenuItem)
		self.viewMenu.add(self.pagesViewMenuItem)
		
		self.logViewMenuItem = JMenuItem("Log",actionPerformed=self.showLogPanel)
		SetStyle(self.logViewMenuItem)
		self.viewMenu.add(self.logViewMenuItem)
		
		# Menu items for Options
		self.threadedMenu = JMenu("Threading")
		SetStyle(self.threadedMenu)
		
		self.multiThreadButton = switchMenuButton("Multi-Threaded")
		SetStyle(self.multiThreadButton)
		self.multiThreadButton.setSelected(True)
				
		self.singleThreadButton = switchMenuButton("Single-Threaded")
		SetStyle(self.singleThreadButton)
		
		self.threadButtonGroup = ButtonGroup()
		self.threadButtonGroup.add(self.multiThreadButton)
		self.threadButtonGroup.add(self.singleThreadButton)
		self.threadedMenu.add(self.multiThreadButton)
		self.threadedMenu.add(self.singleThreadButton)
		
		self.pageLimit=JMenuItem("Page Limit",actionPerformed=self.limitAction)
		SetStyle(self.pageLimit)
		
		self.retrieversMenu = JMenuItem("Retrievers",actionPerformed=self.setRetrieversAction)		
		SetStyle(self.retrieversMenu)
		
		self.parsersMenu = JMenuItem("Parsers",actionPerformed=self.setParsersAction)
		SetStyle(self.parsersMenu)

		self.optionMenu.add(self.threadedMenu)
		self.optionMenu.add(self.pageLimit)
		self.optionMenu.add(self.retrieversMenu)
		self.optionMenu.add(self.parsersMenu)		
		
		## add help menu with an about menuItem
		self.about = JMenuItem("About",actionPerformed=self.aboutAction)
		SetStyle(self.about)
		self.helpJMenu.add(self.about)
		
		#add menus to menubar
		self.add(self.fileMenu)
		self.add(self.viewMenu)
		self.add(self.optionMenu)
		self.add(self.helpJMenu)
		self.setBackground(Color.BLACK)
	
	def DisableOptions(self):
		self.optionMenu.setEnabled(False)
	
	def EnableOptions(self):
		self.optionMenu.setEnabled(True)
		
	def setRetrieversAction(self, event):
		input=JOptionPane.showInputDialog(frame,"Please enter the number of Retrievers you would like to use.\n" +
			"Currently the number of Retrievers is " + str(frame.getRetrievers()))
		frame.setRetrievers(input)    

	def setParsersAction(self, event):
		input=JOptionPane.showInputDialog(frame,"Please enter the number of Parsers you would like to use.\n" +
			"Currently the number of Parsers is " + str(frame.getParsers()))
		frame.setParsers(input)
		
	def aboutAction(self, event):
		JOptionPane.showMessageDialog(frame,"Thank you for selecting Webcrawls\n" +
			"Designed by Paul Ganea, Ralph Feltis, and Tarl Hahn\n\n" +
			"A simple webcrawler that calculates a few statistics as " +
			"it scans webpages for links to crawl")	
			
	def quitAction(self, event):
		sys.exit(0)
		
	def limitAction(self, event):
		input=JOptionPane.showInputDialog(frame,"Please enter the number of Pages you want to retrieve\n" +
			"The current Page Limit is " + str(frame.getPageLimit()))
		frame.setPageLimit(input)		
	  
  	def showReporterPanel(self, event):
  		bgPanel.getLayout().show(bgPanel, REPORTER_PANEL_NAME)

	def showPagesPanel(self, event):
		bgPanel.getLayout().show(bgPanel, PAGES_PANEL_NAME)
		
	def showLogPanel(self, event):
		bgPanel.getLayout().show(bgPanel, LOG_PANEL_NAME)

## Run/Stop Button
def runStopAction(event):
	#test if run then run the crawler
	if (runStopButton.getText() == "Run"):
		runStopButton.setText("Stop") #change button face to stop
		logTextArea.setText("")		
		URLLIST.clear()
		frame.startCrawling()		
		menubar.DisableOptions()
		bean_label.setText(DEFAULT_BEAN_LABEL_TEXT)
	else:
		runStopButton.setText("Run")
		frame.crawler.StopCrawling()
		menubar.EnableOptions()

def printLog():
	while True:
		message = frame.getMessage()
		logTextArea.append("[" + datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + "] " + message + "\n")
		logTextArea.setCaretPosition(logTextArea.getDocument().getLength());


def getReporterText():
	return str(frame.crawler.reporter)


def getReporterHTML():
	Buffer= "<html>"
	for line in getReporterText().split('\n'):
		Buffer+="<br>" + line
	Buffer+="</html>"
	return Buffer

class MyListener(ActionListener):
	def actionPerformed(self, e):
		for i in frame.crawler.reporter.myBeans:
			if not (URLLIST.contains(i)):
				URLLIST.addElement(i)
		if reporterLabel.getText() != getReporterHTML(): 
			reporterLabel.setText(getReporterHTML())
			f = open('collected_data.txt', 'w')
			f.write(str(getReporterText()))
			f.close()	
		
class Hover(ListSelectionListener):
	def valueChanged(self,e):
		if(e.getValueIsAdjusting()==False):
			
			Buffer= "<html>"
			for line in str(URLtxtArea.getSelectedValue()).split('\n'):
				Buffer+="<br>" + line
			Buffer+="</html>"
	
			bean_label.setText(Buffer)
         
class repaintTimer(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self, name='Repaint Timer Thread')
        self.start()

    def run(self):
    	actions= MyListener()  
        tmr = Timer(1000, actions);
        tmr.start()

def SetStyle(component):
	component.setForeground(Color.GREEN)
	component.setBackground(Color.BLACK)
	component.setFont(the_font)
	
	
#constants
frame=GraphicUI()

bgPanel = bgPanel()
frame.add(bgPanel,BorderLayout.CENTER)

## add crawler display and stat display to the background panel	
reporterPanel = displayPanel()
reporterPanel.setLayout(BorderLayout())
bgPanel.add(reporterPanel, REPORTER_PANEL_NAME)

pagesPanel = displayPanel()
pagesPanel.setLayout(BorderLayout())
bgPanel.add(pagesPanel, PAGES_PANEL_NAME)

logPanel = displayPanel()
logPanel.setLayout(BorderLayout())
bgPanel.add(logPanel, LOG_PANEL_NAME)


## add user interface panel
uiPanel = JPanel() 
uiPanel.setBackground(Color(0,0,0))
frame.add(uiPanel,BorderLayout.SOUTH)

runStopButton = JButton("Run",actionPerformed=runStopAction)
runStopButton.setForeground(Color.GREEN)
runStopButton.setBackground(Color.BLACK)
runStopButton.setFont(the_font)
## end run/stop button

uiInputURL = JTextField("http://faculty.washington.edu/gmobus/ ")
uiInputURL.setForeground(Color.GREEN)
uiInputURL.setBackground(Color.BLACK)
uiInputURL.setFont(the_font)

#add components to the User Interface Panel
uiPanel.add(uiInputURL)
uiPanel.add(runStopButton)
##~~ user Interface panel end ~~##
menubar = crawlMenu() 
frame.setJMenuBar(menubar)

# Reporter panel elements
reporterLabel = JLabel(getReporterHTML())
SetStyle(reporterLabel)
reporterLabel.setForeground(Color.RED)
reporterLabel.setVerticalAlignment(JLabel.TOP)
reporterLabel.setBorder(border.EmptyBorder(0, 10, 0, 0))
reporterPanel.add(reporterLabel, BorderLayout.CENTER)

# Log panel elements
logTextArea=JTextArea()
SetStyle(logTextArea)
logTextArea.setForeground(Color.RED)
logScrollPane=JScrollPane(logTextArea)
logPanel.add(logScrollPane)

# Pages panel elements
URLLIST=DefaultListModel()
URLtxtArea=JList(URLLIST)
URLtxtArea.setFixedCellWidth(500)
URLtxtArea.setForeground(Color.GREEN)
URLtxtArea.setBackground(Color.BLACK)
URLtxtArea.setFont(the_font)
URLtxtArea.getSelectionModel().addListSelectionListener(Hover())
URLtextModel=DefaultListModel()
URLText = JList(URLtextModel)
URLScrollBar= JScrollPane(URLtxtArea);
bean_label = JLabel(DEFAULT_BEAN_LABEL_TEXT)
bean_label.setForeground(Color.RED)
bean_label.setFont(the_font)
bean_label.setVerticalAlignment(JLabel.TOP)
bean_label.setBorder(border.EmptyBorder(0, 10, 0, 0))
pagesPanel.add(URLScrollBar, BorderLayout.WEST)
pagesPanel.add(bean_label, BorderLayout.CENTER)

repaintTimer()
UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
frame.setVisible(True)